#pragma once

#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>

namespace Client
{
    enum
    {
        USAGE_ERR = 10,
        SOCKET_ERR,
        SENDTO_ERR,
        RECVFROM_ERR
    };

    using namespace std;
    class udpClient
    {
    public:
        udpClient(const uint16_t &serverPort, const string &serverIp)
            : _serverPort(serverPort), _serverIp(serverIp), _quit(false)
        {
        }

        void initClient()
        {
            // 1.创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sockfd < 0)
            {
                cout << "socket error: " << errno << ": " << strerror(errno) << endl;
                exit(SOCKET_ERR);
            }
            cout << "socket success " << _sockfd << endl;

            // 2.客户端由操作系统生成端口号，操作系统bind，不需要显式给出
        }

        void run()
        {
            // 给谁发，绑定谁的，服务器的ip port
            // struct sockaddr是一个地址，sin_family是地址的协议族，sin_addr.s_addr是ip，sin_port是port
            // 然后将地址sockaddr与套接字_sockfd绑定
            struct sockaddr_in dest_addr;
            bzero(&dest_addr,sizeof(dest_addr));
            dest_addr.sin_family = AF_INET;
            dest_addr.sin_addr.s_addr = inet_addr(_serverIp.c_str()); // ip转为十进制+转为大端
            dest_addr.sin_port = htons(_serverPort);                  // 主机向网络发，转为大端

            string message;
            while (!_quit)
            {
                cout << "请输入#";
                getline(cin, message);

                // 在第一次发送时，操作系统进行bind
                // 这里利用绑定后的套接字（按其绑定的ip port）发数据
                // udpServer中利用绑定后的套接字（按其绑定的ip port）接收数据
                int n = sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
                if (n < 0)
                {
                    cout << "sendto error: " << errno << ": " << strerror(errno) << endl;
                    exit(SENDTO_ERR);
                }

                // 接收服务器回应
                char buf[1024];
                struct sockaddr_in responce_addr;
                socklen_t len = sizeof(responce_addr);
                size_t s = recvfrom(_sockfd, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&responce_addr, &len);
                if (s < 0)
                {
                    cout << "recvfrom error: " << errno << ": " << strerror(errno) << endl;
                    exit(RECVFROM_ERR);
                }
                buf[s] = 0;
                //cout << "服务器返回# " << buf << endl;
                cout<<buf<<endl;
            }
        }

        ~udpClient()
        {}
    private:
        int _sockfd;
        string _serverIp;     // 服务器IP
        uint16_t _serverPort; // 服务器端口号
        bool _quit;
    };

}



